//
//  OosManagedObjectMover.m
//  oos4ios
//
//  Created by Pablo Gonzalez on 5/27/11.
//  Copyright 2011 11870.com. All rights reserved.
//

#import "OosManagedObjectMover.h"

@implementation OosManagedObjectMover

static NSPersistentStoreCoordinator *coordinator;

@synthesize sourceContext = mSourcecontext;
@synthesize targetContext = mTargetContext;
@synthesize result = mResult;

+ (void)initialize
{
    coordinator = [[OosManagedContext context] persistentStoreCoordinator];
}

- (void)dealloc
{
    [mSourcecontext release];
    [mTargetContext release];
    [mResult release];
    [super dealloc];
}

- (id) fetch: (id) object
{
    id result = nil;
    if ([object isKindOfClass:[NSSet class]]) {
        result = [self fetch: [(NSSet *)object allObjects]];
        result = [NSMutableSet setWithArray:result];
    } else if ([object isKindOfClass:[NSArray class]]) {
        NSArray *original = (NSArray *) object;
        NSMutableArray *resultArray;
        resultArray = [NSMutableArray arrayWithCapacity:[original count]];
        for (id item in original) {
            [resultArray addObject:[self fetch: item]];
        }
        result = resultArray;
    } else if ([object isKindOfClass:[NSManagedObject class]]) {
        NSManagedObject *managedObject = (NSManagedObject *) object;
        NSManagedObjectID *objectID = [managedObject objectID];
        managedObject = [mTargetContext objectWithID:objectID];
        [mTargetContext refreshObject:managedObject mergeChanges:YES];
        result = managedObject;
    } else {
        NSLog(@"Can't move: %@", object);
    }
    return result;
}

- (id) move: (id) object
{
    @synchronized (self) {
        self.result = object;
        if (self.sourceContext != self.targetContext) {
            [coordinator lock];
            @try {
                [self.sourceContext processPendingChanges];
            }
            @catch (NSException *exception) {
                NSLog(@"Error processing pending changes");
            }
            @finally {
                // pass
            }
            
            NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
            [notificationCenter addObserver: self 
                                   selector: @selector(threadControllerContextDidSave:) 
                                       name: NSManagedObjectContextDidSaveNotification 
                                     object: self.sourceContext];
            
            @try {
                NSError *error = nil;
                [self.sourceContext save:&error];
                if (error) {
                    self.result = error;
                }
            }
            @catch (NSException *exception) {
                NSLog(@"Error saving target context");
            }
            @finally {
                // pass
            }
            
            [notificationCenter removeObserver: self 
                                          name: NSManagedObjectContextDidSaveNotification
                                        object: self.sourceContext];
            
        } else {
            NSLog(@"Object not moved, same target and sourceContext");
        }
        return self.result;
    }
}

static OosManagedObjectMover *instance;

+ (OosManagedObjectMover *) instance
{
    if (!instance) {
        instance = [OosManagedObjectMover new];
    }
    return instance;
}

+ (id)moveObjectToMaincontext:(id)object
{
    OosManagedObjectMover *mover = [self instance];
    mover.sourceContext = [OosManagedContext context];
    mover.targetContext = [OosManagedContext mainContext];
    return [mover move:object];
}

+ (id)moveObjectFromMaincontext:(id)object
{
    OosManagedObjectMover *mover = [self instance];
    mover.sourceContext = [OosManagedContext mainContext];
    mover.targetContext = [OosManagedContext context];
    return [mover move:object];
}

+ (id) moveObjectToCurrentContext: (id) object
{
    NSManagedObject *managedObject = (NSManagedObject *)object;
    if ([managedObject managedObjectContext] != [OosManagedContext context]) {
        OosManagedObjectMover *mover = [OosManagedObjectMover instance];
        mover.targetContext = [OosManagedContext context];
        mover.sourceContext = [managedObject managedObjectContext];
        managedObject = [mover move:managedObject];
    }
    return managedObject;
}

- (void)threadControllerContextDidSave:(NSNotification*)saveNotification {  
    // need to unlock before we let main thread merge  
    [coordinator unlock];  
    [self performSelectorOnMainThread:@selector(mergeToTargetContext:) 
                           withObject:saveNotification 
                        waitUntilDone:YES];  
}  

- (void)mergeToTargetContext:(NSNotification*)saveNotification {  
    NSError *error= nil;  
    [mTargetContext mergeChangesFromContextDidSaveNotification:saveNotification];  
    [mTargetContext save:&error];
    if (!error) { 
        self.result = [self fetch:self.result];
    } else {
        self.result = error;
        NSLog(@"%@", [error localizedDescription]);
    }
    
//    [mCallback received:result];
}  

@end
